#pragma once

#include "include/t3sdk.h"
#include "HsManange.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <nlohmann/json.hpp>
#include <fmt/format.h>

using namespace t3sdk;
using nlohmann::json;
using namespace HST3;

struct HST3Response
{
    std::string Function;
    std::string Service;
    std::string Security;
    std::string ShardingInfo;
    std::string RspBody;
};

HST3Response ParseBody(const void *recvData, int recvLen)
{
    HST3Response response;

    IT3Message *message = NewMessage(MessageType::HSAnswer);
    message->AddRef();
    fmt::print("RecvData = {}\n", std::string((char *)recvData, recvLen + 1));

    int ret = message->SetBuff(recvData, recvLen);
    if (ret != 0)
    {
        fmt::print("IT3Message SetBuff failed\n");
        return response;
    }

    fmt::print("Return errno = {}, errorinfo = {}\n", message->GetErrorNo(), message->GetErrorInfo());

    response.Function = message->GetFunction();
    response.Service = message->GetService();
    response.Security = message->GetSecurity();
    response.ShardingInfo = message->GetShardingInfo();
    fmt::print("Function = {}, Service = {}, BodyType = {}, Security = {}, ShardingInfo = {}\n",
               message->GetFunction(),
               message->GetService(), message->GetBodyType(), message->GetSecurity(),
               message->GetShardingInfo());

    int rspLen = 0;
    const void *rsp = message->GetBody(rspLen);

    response.RspBody = std::string((char *)(rsp), rspLen);

    message->Release();
    return response;
}

void ParseLogin(const std::string &loginRsp)
{
    json jstr = json::parse(loginRsp);

    cust_id = jstr["cust_id"];
    client_id = jstr["client_id"];
    fmt::print("login rsp : client_id({}), cust_id({}), last_login_date({})\n\n",
               client_id, cust_id, jstr.at("last_login_date").get<int>());
}

/* 自定义回调函数，继承自IT3Callback,需要用到的函数就具体实现 */
class MyCallback : public IT3Callback
{
public:
    /* IBase接口 */
    unsigned long FUNCTION_CALL_MODE QueryInterface(const char *iid, IBase **ppv) { return 0; }
    unsigned long FUNCTION_CALL_MODE AddRef() { return 0; }
    unsigned long FUNCTION_CALL_MODE Release() { return 0; }

    /* IT3Callback接口函数，具体参考T3sdk开发包 */

    void FUNCTION_CALL_MODE OnConnect(IT3Connection *lpConnection)
    {
        fmt::print("MyCallback::OnConnect\n");
    }

    void FUNCTION_CALL_MODE OnSafeConnect(IT3Connection *lpConnection)
    {
        fmt::print("MyCallback::OnSafeConnect\n");
    }

    void FUNCTION_CALL_MODE OnRegister(IT3Connection *lpConnection)
    {
        fmt::print("MyCallback::OnRegister\n");
    }

    void FUNCTION_CALL_MODE OnClose(IT3Connection *lpConnection)
    {
        fmt::print("MyCallback::OnClose\n");
    }

    void FUNCTION_CALL_MODE OnReceiveNotify(IT3Connection *lpConnection, int hSend, const void *lpData, int nLength)
    {
        fmt::print("MyCallback::OnReceiveNotify\n");
    }

    void FUNCTION_CALL_MODE OnReceived(IT3Connection *lpConnection, int hSend, const void *lpData, int nLength)
    {
        fmt::print("[MyCallback::OnReceived] conn = {}, hSend = {}\n", fmt::ptr(lpConnection), hSend);

        auto rsp = ParseBody(lpData, nLength);
        if (rsp.Function == "iic.getAuthuserPasswordLoginExt")
        {
            ParseLogin(rsp.RspBody);

            QueryFundAccount();
            auto data = hsRequest.SerialStr();
            int ret = lpConnection->Send(data.first, data.second, 1);
            fmt::print("[Send] conn = {}, hSend = {}\n", fmt::ptr(lpConnection), ret);
        }
        else
        {
        }
    }
};
